import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import router from '../router'
import { message } from 'ant-design-vue';
import { showLoading, hideLoading } from '@/plugins/loading'
import { IResult } from "./Interfaces"
import { clearLoginCache, getLocal, getSession, getTokenKey, setLocal, singleExecute } from '@/util/utils';

export class AxiosInstanceWrapper {
  private instance: AxiosInstance;
  /**
   * 是否需要等到
   * @param idLoading
   */
  constructor(idLoading: boolean) {
    this.instance = new AxiosHttpClient(idLoading).getInstance()
  }

  public get(url: string, value?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<IResult>> {
    if (!config) {
      config = {
      }
    }
    config.params = value
    return <Promise<AxiosResponse<IResult>>>this.instance.get(url, config)
  }

  public post(url: string, value: any, config?: AxiosRequestConfig): Promise<AxiosResponse<IResult>> {
    return <Promise<AxiosResponse<IResult>>>this.instance.post(url, value, config)
  }
}

/**
 * 研发路由，帮助研发调试接口
 * @param config 
 */
const devRoute = (config:AxiosRequestConfig) => {
  const pathRoute = localStorage.getItem('pathRoute')
  if(pathRoute && typeof pathRoute === 'string'){
    if (!config.headers) {
      config.headers = {}
    }
    config.headers['pathRoute'] = pathRoute
  }
  const serverRoute = localStorage.getItem('serverRoute')
  if(serverRoute && typeof serverRoute === 'string'){
    if (!config.headers) {
      config.headers = {}
    }
    config.headers['serverRoute'] = serverRoute
  }
}

export class AxiosHttpClient {
  private instance: AxiosInstance;
  /**
   * 请求不执行等待
   * 默认等待
   */
  private idLoading: boolean = true;

  constructor(idLoading: boolean) {
    // 创建axios实例
    this.instance = axios.create({ timeout: 1000 * 1000 });
    // 初始化拦截器
    this.initInterceptors();
    this.idLoading = idLoading
  }

  // 为了让http.ts中获取初始化好的axios实例
  public getInstance() {
    return this.instance;
  }


  // 初始化拦截器
  public initInterceptors() {
    // 设置post请求头
    this.instance.defaults.headers.post['Content-Type'] = 'application/json';
    /**
     * 请求拦截器
     * 每次请求前，如果存在token则在请求头中携带token
     */
    this.instance.interceptors.request.use(
      (config) => {
        if (this.idLoading) {
          showLoading()
        }
        const tokenKey = getTokenKey()
        const token = getLocal(tokenKey)
        if (!config.headers) {
            config.headers = {}
        }
        if (token && typeof token === 'string') {
            config.headers[tokenKey] = token
        }
        let owner: any = getSession("devcloud-auth");
        if(owner){
            config.headers['sys-id'] = owner.sysId
        }
        devRoute(config)

        return config;
      },
      (error) => {
        message.error(error)
        console.log(error)
      },
    );

    this.instance.interceptors.response.use(
      (response) => {
        if (this.idLoading) {
          hideLoading()
        }
        let res = response.data;
        if ('0' == res.code) {
          res.success = true
          return response;
        }
        if ('2000000' == res.code) {
          const tokenKey = getTokenKey()
          const tokenVal = response.headers[tokenKey]
          setLocal(tokenKey, tokenVal)
          res.success = true
          return response;
        }
        res.success = false
        if (res.code >= 4000100 && res.code < 4000200) {
          clearLoginCache()
          router.push('/login')
          singleExecute(() => { message.error(res.msg) }, res.msg, 5000)
        } else {
          message.error(res.msg);
        }
        return Promise.resolve(response);
      },
      (error) => {
        if (this.idLoading) {
          hideLoading()
        }
        const { response } = error;
        if (response) {
          // 请求已发出，但是不在2xx的范围
          this.errorHandle(response);
          return Promise.resolve({ data: { success: false } });
        } else {
          // 处理断网的情况
          // eg:请求超时或断网时，更新state的network状态
          // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
          // 关于断网组件中的刷新重新获取数据，会在断网组件中说明
          // ElMessage.warning!('网络连接异常,请稍后再试!');
          message.error('网络连接异常,请稍后再试!');
          return Promise.resolve({ data: { success: false } });
        }
      }
    )
  }

  /**
   * http握手错误
   * @param res  响应回调,根据不同响应进行不同操作
   */
  private errorHandle(res: any) {
    // 状态码判断
    switch (res.status) {
      case 401:
        break;
      case 403:
        break;
      case 404:
        message.error('请求的资源不存在');
        break;
      default:
        message.error('网连接错误');
    }
  }
}
